The built-in [React Native Component Development Environment](https://bit.cloud/teambit/react/react-native) is a concrete composition of the [Env Aspect](https://bit.cloud/teambit/envs/envs). Use it when getting started with React Native components with Bit and later as a base for any future customization of your ReactNative-based workflow.

React Native environment is composed out of the base [React Environment](https://bit.cloud/teambit/react/react) with some specific overrides for dependency management.

## Use React Native environment

To use this environment for your components, add it to any of the `variants` in your `workspace.jsonc` file as follows:

```json title="workspace.jsonc"
{
  "teambit.workspace/variants": {
    "some/path": {
      "teambit.react/react-native": {}
    }
  }
}
```

## Create React Native components

React Native implements several component templates:

- `react-native-env` boilerplate for customizing configuration.

Use any of these templates with the `bit create` command:

```sh
bit create <template name> [components...]
```

## Default Configuration and Services

React Native, like all over Environments must implement a set of Service Handlers. For each service, React Native compose a different tool and config by default.

> React Native is a composition of the React environment with some specific modifications. Most of the links here direct to the actual configs in React environment.

| Service              | Aspect                                                        | Base Configuration                                                                                                                   |
| -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Compilation          | [TypeScript](https://bit.cloud/teambit/typescript/typescript) | [tsconfig.json](https://bit.cloud/teambit/react/react/~code/typescript/tsconfig.json)                                                |
| Testing              | **Jest**                                                      | [jest.config.js](https://bit.cloud/teambit/react/react/~code/jest/jest.config.js)                                                    |
| Linting              | **ESLint**                                                    | [eslintrc.ts](https://bit.cloud/teambit/react/react/~code/eslint/eslintrc.ts)                                                        |
| DevServer            | **Webpack**                                                   | [webpack.config.preview.cloud.ts](https://bit.cloud/teambit/react/react/~code/webpack/webpack.config.preview.cloud.ts)               |
| Preview (simulation) | **Webpack**                                                   | [webpack.config.preview.ts](https://bit.cloud/teambit/react/react/~code/webpack/webpack.config.preview.ts)                           |
| Package              | **PKG**                                                       | Base `package.json` props from [TypeScript Aspect](https://bit.cloud/teambit/typescript/typescript/~code/typescript.main.runtime.ts) |
| Bundling             | **Webpack**                                                   | [webpack.config.preview.ts](https://bit.cloud/teambit/react/react/~code/webpack/webpack.config.preview.ts)                           |
| Documentation        | _Core implementation_                                         | [Docs template](https://bit.cloud/teambit/react/react/~code/docs/index.tsx)                                                          |
| Build pipeline       | [Builder](https://bit.cloud/teambit/pipelines/builder)        | [Build pipeline](https://bit.cloud/teambit/react/react/~code/react-native.env.ts)                                                    |
| Dependencies         | _Core implementation_                                         | [Env-dependencies](https://bit.cloud/teambit/react/react-native/~code/react-native.env.ts)                                           |
| Component Generator  | [Generator](https://bit.cloud/teambit/generator/generator)    | [example template](https://bit.cloud/react/react-native/~code/templates/react-native-component.ts)                                   |

## Customize environment

All environments are extendible. You can take any pre-existing environment, and create a component to extend it. That component can then use APIs to:

- Override default configurations.
- Replace composed tools with others (for example - use Babel instead of TypeScript).
- Add new services and capabilities.

### Create an extension

The first step is to create a component that extends React Native. Use the `react-native-env` template from React Native env.

```sh
bit create react-native-env extensions/custom-react-native
```

As with any component, environments must themselves have an environment which compiles, builds, transpiles, etc, them. Bit has a special environment that knows how to create other environments - `teambit.harmony/aspect`. So for any component that is meant to be a Bit environment, you must set `teambit.harmony/aspect` as the environment for that component.

```json title="add variant for the extension and set the aspect env"
{
  //...
  "teambit.workspace/variants": {
    //...
    "extensions/custom-react-native": {
      "teambit.harmony/aspect": {}
    }
    //...
  }
}
```

Validate the above by running `bit env` and see that the extension-component has `teambit.harmony/aspect` set as an environment.

Now that you have a basic customized extension to start from, you can go ahead and configure it for your components in `workspace.json`:

```json title="edit variants and set the new env"
{
  //...
  "teambit.workspace/variants": {
    //...
    "[some]/[variant]": {
      "[yourscope]/extensions/custom-react-native": {}
    }
    //...
  }
}
```

### Customize configuration

React Native implements a set of APIs you can use to merge your preferred configuration with its defaults. These APIs are called **transformers** and they all start with the `override` pre-fix. Find [Available transformers here](#transformers-api-docs).
In case of a conflict, your config will override the default.

```typescript {4,14} title="Customized TypeScript configuration"
import { EnvsMain, EnvsAspect } from '@teambit/envs';
import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';

const tsconfig = require('./typescript/tsconfig.json');

export class CustomReactNativeExtension {
  constructor(private reactNative: ReactNativeMain) {}

  static dependencies: any = [EnvsAspect, ReactNativeAspect];

  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const customReactNativeEnv = reactNative.compose([reactNative.overrideTsConfig(tsconfig)]);

    envs.registerEnv(customreactNativeEnv);

    return new CustomReactNativeExtension(reactNative);
  }
}
```

> To override any specific configuration it's recommended to create a separate config file with your customized configuration and import it into the main `.extension.ts` file where you can supply it to the relevant **transformers**. See the tsconfig example in the above snippet.

### Composing tools and services

Environments use Environment Services by implementing a special class of methods called Service Handlers.
The supplied transformers allow overriding of these services - for instance the `overrideCompiler` transformer allows overriding the environment's `getCompiler()` method.

The below example uses the `overrideCompiler` transformer to override the `getCompiler()` Service Handler to change the compilation service.

1. Add a Babel config file to your custom environment and import/require it in your `.extension` file
1. Create a new Babel compiler using the Babel aspect, and initialize it with the above babelConfig
1. Use the `compose` Env API to apply the compiler override transformer and add Babel as a transpiler in the environment

```typescript {3,5,10-12,15,17-18,22-23}
import { EnvsMain, EnvsAspect } from '@teambit/envs';
import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';
import { BabelAspect, BabelMain } from '@teambit/babel';

const babelConfig = require('./babel/babel.config');

export class CustomReactNativeExtension {
  constructor(private reactNative: ReactNativeMain) {}

  static dependencies: any = [EnvsAspect, reactNative, BabelAspect];

  static async provider([envs, reactNative, babel]: [EnvsMain, ReactNativeMain, BabelMain]) {
    const babelCompiler = babel.createCompiler({
      babelTransformOptions: babelConfig,
    });

    const customReactNativeEnv = reactNative.compose([
      reactNative.overrideCompiler(babelCompiler),
      reactNative.overrideCompilerTasks([babelCompiler.createTask()]),
    ]);

    envs.registerEnv(customReactNativeEnv);
    return new CustomReactNativeExtension(reactNative);
  }
}
```

### Transformers API docs

Use these APIs to customize the base React Native environment default configuration with your extension. [Read more here](#customizing-configuration).

#### `overrideTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer`

Merges the environment's default TypeScript configuration with the contents of your [typescript configuration file](https://www.typescriptlang.org/handbook/tsconfig-json.html).
This config affects the transpilation carried out when rendering components on the local cloud UI. To override the config used when building components, use `overrideBuildTsConfig` below.

```ts
// ...
const tsconfig = require('./typescript/tsconfig.json');
export class ReactNativeExtension {
// ...

  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideTsConfig(tsconfig)
    ]);
}
// ...
```

#### `overrideBuildTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer`

Merges the environment's default TypeScript configuration with the contents of your [typescript configuration file](https://www.typescriptlang.org/handbook/tsconfig-json.html).
This config affects transpilation of component code during the build process, i.e. in preparation for packaging and exporting the component. To override the local ts config used when rendering components in the local UI, please use `overrideTsConfig` above.

```ts
// ...
const tsconfig = require('./typescript/tsconfig.json');
export class ReactNativeExtension {
// ...

  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideTsConfig(tsconfig)
    ]);
}
// ...
```

#### `overridePreviewConfig(config: Configuration): EnvTransformer`

Merges the Webpack configuration for the 'Preview' environment service, with the contents of your [webpack configuration file](https://webpack.js.org/configuration/).
This webpack configuration is used for building and rendering your components on the local cloud server.

```ts
// ...
const webpackConfig = require('./webpack/webpack.config');
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overridePreviewConfig(webpackConfig)
    ]);
}
// ...
```

#### `overrideDevServerConfig(config: Configuration): EnvTransformer`

Merges the Webpack configuration for the 'DevServer' environment service, with the contents of your [webpack configuration file](https://webpack.js.org/configuration/).
This configuration is used for building and rendering the cloud server UI (but not your components, which use the PreviewConfig)

```ts
// ...
const webpackConfig = require('./webpack/webpack.config');
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideDevServerConfig(webpackConfig)
    ]);
}
// ...
```

#### `overrideJestConfig(jestConfigPath: string): EnvTransformer`

Merges the default configuration for the Jest test runner with the contents of your ([jest.config configuration file](https://jestjs.io/en/configuration)).

```ts
// ...
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideJestConfig(require.resolve('./jest/jest.config'))
    ]);
}
// ...
```

#### `overrideBuildPipe(tasks: BuildTask[]): EnvTransformer`

This method receives an array of build tasks. It merges the provided tasks with the environment's default build pipeline (initiated either on a `bit tag` or `bit build` command).

```ts
// ...
// Import the task
import { CustomTask } from './custom.task'
export class CustomReactNative {
  // ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    // Get the environment's default build pipeline using the 'getBuildPipe' service handler
    const reactNativePipe = reactNative.env.getBuildPipe()
    // Add the custom task to the end of the build tasks sequence.
    const tasks = [...reactNativePipe, new CustomTask()]
    const newReactNativeEnv = reactNative.compose([reactNative.overrideBuildPipe(tasks)])
    // ...
  }
}
```

#### `overrideDependencies(dependencyPolicy: DependenciesPolicy): EnvTransformer`

This method receives a dependency-policy object and merges it with the environment's default dependency policy for components using this environment.
Each key-value pair in a dependency-policy object signifies the package and the version to be used. Use also the `-` and `+` notation to signify a module should moved between dependency types (cloud, peer or standard).

```js
// ...
const newDependencies = {
  cloudDependencies: {
    '@types/jest': '~26.0.9'
  }
}

export class CustomReactNative {
  // ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideDependencies(newDependencies)
    ])
    // ...
  }
}
```

#### `overridePackageJsonProps(props: PackageJsonProps): EnvTransformer`

Merges the provide props with the default properties added to the `package.json` file of every package generated from components using this environment.

```ts
// ...
const newPackageProps = {
  main: 'dist/{main}.js',
  types: '{main}.ts'
}

export class CustomReactNative {
  // ...
  static async provider([envs, reactNative].: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overridePackageJsonProps(newPackageProps)
    ])
    // ...
  }
}
```

The built-in [React Native Component Development Environment](https://bit.cloud/teambit/react/react-native) is a concrete composition of the [Env Aspect](https://bit.cloud/teambit/envs/envs). It compose different tools and configs that fit practices implemented in [Create React Native App](https://create-react-app.cloud). Use it when getting started with React Native components with Bit and later as a base for any future customization of your React-Native-based workflow.

React Native environment is composed out of the base [React Environment](https://bit.cloud/teambit/react/react) with some specific configuration overrides.

## Use React Native environment

To use this environment for your components, add it to any of the `variants` in your `workspace.jsonc` file as follows:

```json title="workspace.jsonc"
{
  "teambit.workspace/variants": {
    "[some]/[path]": {
      "teambit.react/react-native": {}
    }
  }
}
```

## Create React Native components

React implements several component templates:

- `reactnative-env` boilerplate for customizing configuration.

Use any of these templates with the `bit create` command:

```sh
bit create <template name> [components...]
```

## Runtime (framework) dependencies

Similar to many Frontend frameworks React Native must have a singleton instance in your app's runtime. When building reuseable components we need to adhere to that and have `react` and `react-native` set as `peerDependencies`, thus allowing the consuming app to determine runtime version. React environment implements this via the **Dependencies** service which is used to override [dependency-resolver](https://bit.cloud/teambit/dependencies/dependency-resolver) and set your prefered dependencies.
It is recommended to for you to extend the base React environment and define a semantic version rule to fit your current tech stack and guidelines for reuseable React components.

## Default Configuration and Services

React Native, like all over Environments must implement a set of Service Handlers. For each service, React Native compose a different tool and config by default.

> React Native is a composition of the React environment with some specific modifications. Most of the links here direct to the actual configs in React environment.

| Service              | Aspect                                                        | Base Configuration                                                                                                                   |
| -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Compilation          | [TypeScript](https://bit.cloud/teambit/typescript/typescript) | [tsconfig.json](https://bit.cloud/teambit/react/react/~code/typescript/tsconfig.json)                                                |
| Testing              | **Jest**                                                      | [jest.config.js](https://bit.cloud/teambit/react/react-native/~code/jest/jest.config.js)                                             |
| Linting              | **ESLint**                                                    | [eslintrc.ts](https://bit.cloud/teambit/react/react/~code/eslint/eslintrc.ts)                                                        |
| DevServer            | **Webpack**                                                   | [webpack.config.preview.cloud.ts](https://bit.cloud/teambit/react/react-native/~code/webpack/webpack.config.js)                      |
| Preview (simulation) | **Webpack**                                                   | [webpack.config.preview.ts](https://bit.cloud/teambit/react/react-native/~code/webpack/webpack.config.js)                            |
| Package              | **PKG**                                                       | Base `package.json` props from [TypeScript Aspect](https://bit.cloud/teambit/typescript/typescript/~code/typescript.main.runtime.ts) |
| Bundling             | **Webpack**                                                   | [webpack.config.preview.ts](https://bit.cloud/teambit/react/react-native/~code/webpack/webpack.config.js)                            |
| Documentation        | _Core implementation_                                         | [Docs template](https://bit.cloud/teambit/react/react/~code/docs/index.tsx)                                                          |
| Build pipeline       | [Builder](https://bit.cloud/teambit/pipelines/builder)        | [Build pipeline](https://bit.cloud/teambit/react/react/~code/react.env.ts)                                                           |
| Dependencies         | _Core implementation_                                         | [Env-dependencies](https://bit.cloud/teambit/react/react-native/~code/react-native.main.runtime.ts)                                  |
| Component Generator  | [Generator](https://bit.cloud/teambit/generator/generator)    | [example template](https://bit.cloud/react/react-native/~code/templates/reactnative-component.ts)                                    |

## Customize environment

All environments are extendible. You can take any pre-existing environment, and create a component to extend it. That component can then use APIs to:

- Override default configurations.
- Replace composed tools with others (for example - use Babel instead of TypeScript).
- Add new services and capabilities.

### Create an extension

The first step is to create a component that extends React Native. Use the `react-native-env` template from React env.

```sh
bit create react-native-env extensions/custom-react-native
```

After you created your extension you need configure it to be a Bit Aspect. This is because environments are actually aspects that extends Bit's core functionality to support your cloudelopment workflow. To do this edit your workspace.jsonc and set `teambit.harmony/aspect` as the environment applied on the extension you created:

```json title="add variant for the extension and set the aspect env"
{
  //...
  "teambit.workspace/variants": {
    //...
    "extensions/custom-react-native": {
      "teambit.harmony/aspect": {}
    }
    //...
  }
}
```

Validate it by running `bit env` and see that the extension-component has `teambit.harmony/aspect` set as an environment.

Now that you have a base extension to start from, you can already go ahead and configure it for your components in `workspace.json`:

```json title="edit variants and set the new env"
{
  //...
  "teambit.workspace/variants": {
    //...
    "[some]/[variant]": {
      "[yourscope]/extensions/custom-react-native": {}
    }
    //...
  }
}
```

### Customize configuration

React implements a set of APIs you can use to merge you preferred configuration with its defaults. These APIs are called **transformers** and they all start with the `override` pre-fix. Find all [Available transformers here](#transformers-api-docs).
In case of a conflict, your config will override the default.

```typescript {4,13} title="Customized TypeScript configuration"
import { EnvsMain, EnvsAspect } from '@teambit/envs';
import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';

const tsconfig = require('./typescript/tsconfig.json');

export class CustomReactNativeExtension {
  constructor(private reactNative: ReactNativeMain) {}

  static dependencies: any = [EnvsAspect, ReactNativeAspect];

  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const customReactNativeExtension = reactNative.compose([reactNative.overrideTsConfig(tsconfig)]);

    envs.registerEnv(customReactNativeExtension);

    return new CustomReactNativeExtension(reactNative);
  }
}
```

> To override any specific configuration it's recommended to create a config file for the specific tool and import it to any of the **transformers**.

### Composing tools and services

Environments use Environment Services by implementing a special class of methods called Service Handlers.
You can override an environment's compiler replacing its Compiler Service Handler with the method `getCompiler()`.
[Find all service handlers here](#service-providers-api-docs).

The below example uses a Service Handler to change compilation service.

1. Import the Babel extension component to configure it and set it as the new compiler
1. Import your Babel config
1. Set the necessary dependencies to be injected (by Bit) into the following 'provider' function
1. Instantiate a new Babel compiler with the 'babelConfig' configurations
1. use the `compose` Env API to register a new Service Hanlder

```typescript {3,5,10-13,15-16,19-21}
import { EnvsMain, EnvsAspect } from '@teambit/envs';
import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';
import { BabelAspect, BabelMain } from '@teambit/babel';

const babelConfig = require('./babel/babel.config');

export class CustomReactNativeExtension {
  constructor(private reactNative: ReactNativeMain) {}

  static dependencies: any = [EnvsAspect, ReactNativeAspect, BabelAspect];

  static async provider([envs, reactNative, babel]: [EnvsMain, ReactNativeMain, BabelMain]) {
    const babelCompiler = babel.createCompiler({
      babelTransformOptions: babelConfig,
    });

    const customReactNativeExtension = reactNative.compose([
      reactNative.overrideCompiler(babelCompiler),
      reactNative.overrideCompilerTasks([babelCompiler.createTask()]),
    ]);

    envs.registerEnv(customReactNativeExtension);
    return new CustomReactNativeExtension(reactNative);
  }
}
```

### Transformers API docs

Use these APIs to customize React environment default configuration with your extension. [React more here](#customizing-configuration).

#### `overrideTsConfig(tsconfig: TsConfigSourceFile): EnvTransformer`

Merge the environment's default TypeScript configurations with a new ([tsconfig.json](https://www.typescriptlang.org/handbook/tsconfig-json.html)) configuration file.

```ts
// ...
const tsconfig = require('./typescript/tsconfig.json');
export class ReactNativeExtension {
// ...

  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideTsConfig(tsconfig)
    ]);
}
// ...
```

#### `overridePreviewConfig(config: Configuration): EnvTransformer`

Merge the Webpack configurations for the 'Preview' environment service, with a new ([webpack.config.js](https://webpack.js.org/configuration/)) configuration file.

```ts
// ...
const webpackConfig = require('./webpack/webpack.config');
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overridePreviewConfig(webpackConfig)
    ]);
}
// ...
```

#### `overrideDevServerConfig(config: Configuration): EnvTransformer`

Merge the Webpack configurations for the 'DevServer' environment service, with a new ([webpack.config.js](https://webpack.js.org/configuration/)) configuration file.

```ts
// ...
const webpackConfig = require('./webpack/webpack.config');
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideDevServerConfig(webpackConfig)
    ]);
}
// ...
```

#### `overrideJestConfig(jestConfigPath: string): EnvTransformer`

This method receives a path (as a string) to a configuration file . Overrides the default configurations for the Jest test runner with a new ([jest.config](https://jestjs.io/en/configuration)) configuration file. This is done by passing the _path_ to the file as an argument.

```ts
// ...
export class ReactNativeExtension {
// ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([
      reactNative.overrideJestConfig(require.resolve('./jest/jest.config'))
    ]);
}
// ...
```

#### `overrideBuildPipe(tasks: BuildTask[]): EnvTransformer`

This method receives an array of Bit tasks. It overrides the build pipeline of a component (initiated either on a `bit tag` or `bit build` command).

```ts
// ...
// Import the task
import { CustomTask } from './custom.task';
export class ReactNative {
  // ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    // Get the environment's default build pipeline using the 'getBuildPipe' service handler
    const reactNativePipe = reactNative.env.getBuildPipe();
    // Add the custom task to the end of the build tasks sequence.
    const tasks = [...reactNativePipe, new CustomTask()];
    const newReactNativeEnv = reactNative.compose([reactNative.overrideBuildPipe(tasks)]);
    // ...
  }
}
```

#### `overrideDependencies(dependencyPolicy: DependenciesPolicy): EnvTransformer`

This method receives a Bit dependency-policy object. It overrides the default dependency policy for components using this environment.
Each key-value pair in a dependency-policy object signifies the package and the version to be used. It also uses the `-` notation to signify a module should not be defined as a dependency of a certain type (cloud, peer or standard).

```js
// ...
const newDependencies = {
  cloudDependencies: {
    '@types/jest': '~26.0.9',
  },
};

export class CustomReactNative {
  // ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([reactNative.overrideDependencies(newDependencies)]);
    // ...
  }
}
```

> The above example shows the 'React Native' library being removed as a (runtime) dependency and added as a peer dependency.

#### `overridePackageJsonProps(props: PackageJsonProps): EnvTransformer`

Overrides the default properties added to the `package.json` file of every package generated from components using this environment.

```ts
// ...
const newPackageProps = {
  main: 'dist/{main}.js',
  types: '{main}.ts',
};

export class CustomReactNative {
  // ...
  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const newReactNativeEnv = reactNative.compose([reactNative.overridePackageJsonProps(newPackageProps)]);
    // ...
  }
}
```

### Service providers API docs

Use these APIs to customize React environment default configuration with your extension. [Read more here](#composing-tools-and-services).

#### `getTester(...args : any[]): Tester`

Returns a test runner to be used by the Tester service.

```ts
export class ReactNativeEnv implements Environment {
  constructor(
    // ...

    // The Jest Aspect
    private jestAspect: JestMain
  ) {}
  // ...
  getTester(jestConfigPath: string, jestModule = jest): Tester {
    const jestConfig = require.resolve('./jest/jest.config');
    return this.jestAspect.createTester(jestConfig);
  }
}
```

#### `getCompiler(...args : any[]): Compiler`

Returns a compiler to be used by the Compiler service.

```ts
export class ReactNativeEnv implements Environment {
constructor(
    // ...
    // The TypeScript aspect
    private tsAspect: TypescriptMain
){}
// ...
getCompiler() {
    const tsConfig = require.resolve('./typescript/tsconfig.json')
    return this.tsAspect.createCompiler(tsConfig);
}
```

#### `getLinter(...args : any[]): Linter`

Returns a linter to be used by the Linter service.

```ts
export class ReactNativeEnv implements Environment {
    constructor(){
        // ...
        // The ESLint aspect
        private eslint: ESLintMain
    }
    // ...
    getLinter() {
        const eslintConfig = require.resolve('./eslint/eslintrc')
        return this.eslint.createLinter({
            config: eslintConfig,
            // resolve all plugins from the react environment
            pluginPath: __dirname,
        });
    }
}
```

#### `getDevServer(...args : any[]): DevServer`

Returns a DevServer to be used by the DevServer service. (A DevServer is essentially the combination of the bundler configurations, together with a specified 'listen' port number)

```ts
export class ReactNativeEnv implements Environment {
  constructor(
    // ...
    // The Webpack aspect
    private webpack: WebpackMain
  ) {}
  // ...
  getDevServer(): DevServer {
    const withDocs = Object.assign(context, {
      entry: context.entry.concat([require.resolve('./docs')]),
    });
    return this.webpack.createDevServer(withDocs, webpackConfig);
  }
}
```

> The above example runs the cloud server with the environment's documentation template.

#### `getDocsTemplate(...args : any[]): string`

Returns the path to the documentation template files, to be used by the Documentation service.

For example (see docs files [here](https://github.com/teambit/bit/tree/master/scopes/react/react/docs)):

```ts
export class ReactNativeEnv implements Environment {
  // ...
  getDocsTemplate() {
    return require.resolve('./docs');
  }
}
```

#### `getPackageJsonProps(...args : any[]): object`

Returns an object that defines the `package.json` properties of the packages generated for components handled by this environment. This configuration is used by the Packager service.

```ts
export class ReactNativeEnv implements Environment {
  // ...
  getPackageJsonProps() {
    return {
      main: 'dist/{main}.js',
      types: '{main}.ts',
    };
  }
}
```

> As with any other 'merging' process, the properties defined in the above returned object will be added to configurations set by Bit.
> Conflicting properties will be overridden by the properties that are set here.
> Configurations that are set here may also be overridden, either by the 'pkg aspect' or by workspace configurations set using the 'variants API'.

#### `getDependencies(component: any): Promise<DependencyList>`

Returns an object that defines the default dependencies for components handled by this environment. The returned object is used by the Dependencies service.

```ts
export class ReactNativeEnv implements Environment {
  // ...
  async getDependencies() {
    return {
      dependencies: {
        react: '-',
      },
      cloudDependencies: {
        '@types/react': '16.9.43',
        '@types/jest': '~26.0.9',
      },
      peerDependencies: {
        react: '^16.13.1',
        'react-dom': '^16.13.1',
      },
    };
  }
}
```

> As with any other 'merging' process, the properties defined in the above returned object will be added to configurations set by Bit.
> Conflicting properties will be overridden by the properties that are set here.
> Configurations that are set here may also be overridden, either by the 'Dependency Resolver aspect' or by workspace configurations set using the 'variants API'.

#### `getBuildPipe(...args : any[]): BuildTask[]`

Returns an array of build tasks to be used by the Builder service. Tasks will be added after and before Bit's pre-configured build tasks.

```ts
export class ReactNativeEnv implements Environment {
  constructor(
    // ...
    // The Compiler aspect
    private compiler: CompilerMain,
    // The Tester aspect
    private tester: TesterMain
  ) {}
  getBuildPipe(): BuildTask[] {
    return [this.compiler.createTask('StencilCompiler', this.getCompiler()), this.tester.task];
  }
}
```

## FAQ

### Compositions issues

```
You may need an appropriate loader to handle this file type...
```

This error can show up for multiple reason, and one of the most popular is because we use a library in a React Native component that uses Native API's.  
As the local Bit Dev Server runs on the Web it can't work properly with API's that are meant to be run on a mobile cloudice.  
So components that are using a library that use Native API's cannot be rendered on the web, because the Native API's are unavailable.

One way to solve it is to see if the library has support for Web and update your code to also be Web compatible.  
If not, the second way to solve this is to search for a parallel library with Web support and make a Webpack aliases in a Bit React Native extension inside your project, and then configure the extension to make a Webpack alises.

If for some reason a library doesn't have a parallel library for the web and doesn't have built in Websupport, you can't make the composition work on the local Bit cloud server.

For example, [`react-native-svg`](https://github.com/react-native-svg/react-native-svg) library has a parallel library called [`react-native-svg-web`](https://github.com/bakerface/react-native-svg-web).  
Let's [create a React Native extension](#create-an-extension) and add a `webpack-transformers.ts` file in the extension under `webpack` folder, the file looks like this:

```ts
import { WebpackConfigTransformer, WebpackConfigMutator, WebpackConfigTransformContext } from '@teambit/webpack';

/**
 * Transformation to apply for both preview and cloud server
 * @param config
 * @param _context
 */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function commonTransformation(config: WebpackConfigMutator, _context: WebpackConfigTransformContext) {
  // Merge config with the webpack.config.js file - adding handlebars support
  // config.merge([webpackConfig]);
  config.addAliases({
    'react-native-svg': require.resolve('react-native-svg-web'),
    'react-native-web': require.resolve('react-native-web'),
  });
  return config;
}

/**
 * Transformation for the preview only
 * @param config
 * @param context
 * @returns
 */
export const previewConfigTransformer: WebpackConfigTransformer = (
  config: WebpackConfigMutator,
  context: WebpackConfigTransformContext
) => {
  const newConfig = commonTransformation(config, context);
  return newConfig;
};

/**
 * Transformation for the cloud server only
 * @param config
 * @param context
 * @returns
 */
export const cloudServerConfigTransformer: WebpackConfigTransformer = (
  config: WebpackConfigMutator,
  context: WebpackConfigTransformContext
) => {
  const newConfig = commonTransformation(config, context);
  return newConfig;
};
```

And then in the main file of the extension we created, let's add the import of the Webpack transformers:

```ts
import { EnvsMain, EnvsAspect } from '@teambit/envs';
import { ReactNativeAspect, ReactNativeMain } from '@teambit/react-native';
import { previewConfigTransformer, cloudServerConfigTransformer } from './webpack/webpack-transformers';

export class CustomReactNativeExtension {
  constructor(private reactNative: ReactNativeMain) {}

  static dependencies: any = [EnvsAspect, ReactNativeAspect];

  static async provider([envs, reactNative]: [EnvsMain, ReactNativeMain]) {
    const CustomReactNativeEnv = reactNative.compose([
      /*
        Use any of the "reactNative.override..." transformers to
      */
      reactNative.useWebpack({
        previewConfig: [previewConfigTransformer],
        cloudServerConfig: [cloudServerConfigTransformer],
      }),
    ]);

    envs.registerEnv(CustomReactNativeEnv);

    return new CustomReactNativeExtension(reactNative);
  }
}
```

This will add the Webpack aliases to the Webpack configurations and solve the issue.  
One last thing we need to do, is to add the peer dependencies of the parallel library we use to the dependency resolver of the extension in the variants section in `workspace.jsonc` file:

```json
{
  "teambit.workspace/variants": {
    // ...
    "[some]/[variant]": {
      "[yourscope]/extensions/custom-react-native": {}
    },
    "extensions/custom-react-native": {
      "teambit.harmony/aspect": {},
      "teambit.dependencies/dependency-resolver": {
        "policy": {
          "dependencies": {
            "react-native-svg-web": "1.0.9",
            "react-native-web": "0.16.2",
            "prop-types": "15.7.2"
          }
        }
      }
    }
    // ...
  }
}
```

In this case `react-native-svg-web` has these dependencies in the peer dependencies:

```json
"peerDependencies": {
  "prop-types": "*",
  "react": "*",
  "react-native-web": ">= 0.10.1"
},
```

So we need to add them as the dependencies of the extension so it will work properly.  
Now every component that will use the `react-native-svg` library will work fine with the compositions, and this solution can be used for every other library that use Native API's.
